﻿
using Microsoft.CodeAnalysis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace DynamicCode.Compilation
{
    public sealed class DynamicCodeBuilder : BaseDynamicCodeBuilder
    {

        public DynamicCodeParameterInfo ParameterInfo { get; private set; }

        public DynamicCodeBuilder(string codetemplate, DynamicCodeParameterInfo parameterInfo) : base(codetemplate)
        {
            if (parameterInfo is null)
            {
                throw new ArgumentNullException(nameof(parameterInfo));
            }

            if (parameterInfo.ParameterType is null)
            {
                throw new ArgumentNullException(nameof(parameterInfo.ParameterType));
            }

            if (string.IsNullOrWhiteSpace(parameterInfo.Name))
            {
                throw new ArgumentException($"“{nameof(parameterInfo.Name)}”不能为 null 或空白。", nameof(parameterInfo.Name));
            }
            ParameterInfo = parameterInfo;
        }
        public DynamicCodeBuilder(string codetemplate, Type parameterType, string parameterName) : this(codetemplate, new DynamicCodeParameterInfo { ParameterType = parameterType, Name = parameterName })
        {

        }
        protected override IDictionary<string, string> FindVariable(string str)
        {
            var parameterType = ParameterInfo.ParameterType;


            var templates = new Dictionary<string, string>();
            int index = -1;
            bool isbegin = false;
            var parameterName = ParameterInfo.Name;
            for (int i = 0; i < str.Length; i++)
            {
                if (str[i] == '@')
                {
                    if (!isbegin)
                    {
                        isbegin = true;
                        index = i;
                        continue;
                    }
                    isbegin = false;
                    var length = i - index;
                    var key = str.Substring(index, length + 1);
                    if (key == "@@") continue;
                    if (!templates.ContainsKey(key))
                    {
                        var propertyname = str.Substring(index + 1, length - 1);
                        var prop = parameterType.GetProperty(propertyname);
                        if (prop == null) throw new EntryPointNotFoundException($"{parameterType.FullName}中不存在属性[{propertyname}] ");
                        templates.Add(key, $"{parameterName}.{propertyname}");
                    }
                }
            }

            return templates;
        }


        public override Type[] Grenerate(DynamicCodeItem[] dBEntities)
        {
            var group = dBEntities.GroupBy(n => n.Code);
            foreach (var item in group)
            {
                if (item.Count() > 1) throw new DynamicCodeException($"Code[{item.Key}]重复");
            }

            string[] codeBuilder = dBEntities.Select(dBEntity =>
            {
                var variable = FindVariable(dBEntity.Content);

                Verification(variable);
                string content = Replace(dBEntity.Content, variable, true);

                var code = Replace(CodeTemplate, new Dictionary<string, string> { { "@code@", dBEntity.Code }, { "@content@", content } });
                return code;
            }).ToArray();

            var types = GenerateCode(codeBuilder);
            return types;
        }
        protected override void Verification(IDictionary<string, string> variable)
        {
            var parameterType = ParameterInfo.ParameterType;
            var properties = parameterType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
            var keys = variable.Keys.Select(n => n.Substring(1, n.Length - 2)).ToArray();
            foreach (var item in keys)
            {
                if (properties.Any(n => n.Name == item)) continue;
                throw new EntryPointNotFoundException($"{parameterType.FullName}中不存在属性[{item}] ");
            }
        }

    }
}
